package com.example.gcmtest1.httpserver;

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.net.Socket;

import org.apache.http.Header;
import org.apache.http.HttpEntity;
import org.apache.http.HttpException;
import org.apache.http.HttpRequest;
import org.apache.http.HttpResponse;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.client.methods.HttpRequestBase;
import org.apache.http.entity.BasicHttpEntity;
import org.apache.http.entity.ByteArrayEntity;
import org.apache.http.entity.ContentProducer;
import org.apache.http.entity.EntityTemplate;
import org.apache.http.impl.DefaultHttpServerConnection;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.protocol.HttpContext;
import org.apache.http.protocol.HttpRequestHandler;
import org.apache.http.util.EntityUtils;

import android.util.Log;

public class MyHandler1 implements HttpRequestHandler {

	private String logName = "MyHandler1";
	
	@Override
	public void handle(HttpRequest request, HttpResponse response, HttpContext context) throws HttpException, IOException {		
				
		Log.d(logName, "got it");
		String httpMethod = request.getRequestLine().getMethod();
		Log.i(logName, "method=" + httpMethod);
		
		String reqHeaderText = this.listAllHeader(request.getAllHeaders());
		Log.i(logName, reqHeaderText);
		
		String uri = request.getRequestLine().getUri();
		Log.i(logName, "uri=" + uri);
		
		String[] ss = uri.split("/");
		int i = 0;
		for (String s : ss) {
			Log.d(logName, "[" + String.valueOf(i) + "]=" + s);
			i += 1;
		}
		
		String hostName = ss[2];
		String destUri = "http://" + this.getDestinationUrl(ss);
		Log.i(logName, "host=" + hostName);
		Log.i(logName, "destUri=" + destUri);

		this.doProxy(context, request, response, hostName, destUri);
		
		
	}
	
	private void doProxy(HttpContext context, HttpRequest request, HttpResponse response, String host, String destUri) {
		Socket socket = (Socket) context.getAttribute("Socket");
		DefaultHttpServerConnection serverConnection = (DefaultHttpServerConnection) context.getAttribute("ServerConnection");
		
		if (socket != null) {
			Log.i(logName, "Got socket, port: " + String.valueOf(socket.getPort()));
		}
		
		HttpRequestBase httpBase = null;
		
		HttpClient httpClient = new DefaultHttpClient();
		
		try {
			if (request.getRequestLine().getMethod().equals("GET")) {
				httpBase = new HttpGet(destUri);
			} else if (request.getRequestLine().getMethod().equals("POST")) {
				httpBase = new HttpPost(destUri);
			}
			
			for (Header h : request.getAllHeaders()) {
				if (!(h.getName().toLowerCase().equals("host"))) {
					httpBase.addHeader(h);
					Log.d(logName, "Appended Header: " + h.getName() + "=" + h.getValue());
				} else {
					httpBase.addHeader("host", host);
					Log.d(logName, "Appended Header: host=" + host);
					
				}
			}
			
			Log.d(logName, "Sending Request: " + destUri);
			
			 // Execute HTTP Request
	        HttpResponse resp = httpClient.execute(httpBase);
	        InputStream ins = resp.getEntity().getContent();
	        
	        long length = resp.getEntity().getContentLength();
	        
	        Log.d(logName, "==== Response Header ====");
	        String respHeader = this.listAllHeader(resp.getAllHeaders());
	        Log.d(logName, respHeader);
	        	        
	        int position = 0;
	        int chunkSize = 1024 * 1024;
	        byte[] bb = new byte[chunkSize];
	        
	        int readLen;
	        
	        for (Header h : resp.getAllHeaders()) {
	        	if (h.getName().toLowerCase().equals("content-length") == false) {
	        		if (h.getName().toLowerCase().equals("content-type") == true) {
		        		response.addHeader(h.getName(), h.getValue());
		        		Log.d(logName, "set header");
		        	} else {
		        		response.addHeader(h.getName(), h.getValue());
			        	Log.d(logName, "Set " + h.getName() + ":" + h.getValue());      		
		        	}
	        		
	        		
	        	} else {
	        		response.addHeader(h.getName(), String.valueOf(length));
	        	}
	        	
	        }
	        	        
	        String httpString = "HTTP/1.1 200 OK\r\n";
	        for (Header h2 : response.getAllHeaders()) {
	        	httpString = httpString + h2.getName() + ": " + h2.getValue() + "\r\n";
	        }
	        
	        httpString = httpString + "\r\n";
	        
	        Log.d(logName, "httpString=\n" + httpString);
	        
	        byte[] buffer = httpString.toString().getBytes();
	        socket.getOutputStream().write(buffer, 0, buffer.length);	        
	        
	        //ByteArrayOutputStream byteBuffer = new ByteArrayOutputStream();
	        
	        while (position < length) {
	        	readLen = chunkSize;
	        	
	        	if (position + chunkSize > length) {
	        		readLen = (int) (length - position);
	        	}
	        	
	        	if (readLen != chunkSize) {
	        		bb = new byte[readLen];	
	        	}
	        	
	        	int len = ins.read(bb);
	        	Log.d(logName, "len=" + String.valueOf(len) + ", available=" + String.valueOf(ins.available()));
	        	
	        	socket.getOutputStream().write(bb, 0, len);
	        	//byteBuffer.write(bb, 0, len);        	
	        		        		        		        		        		        			        	        
	        	position = position + len;
	        	Log.d(logName, "position:" + String.valueOf(position));
	        	
	        }
	        
	        ins.close();
	        
	        //serverConnection.close();
	        //socket.close();
	        
	        /*
        	ByteArrayEntity bEntity = new ByteArrayEntity(byteBuffer.toByteArray());
        	response.setStatusCode(200);
        	response.setEntity(bEntity);
	        */
	        
	        /*
	        HttpEntity entity = new EntityTemplate(new ContentProducer() {
                public void writeTo(final OutputStream outstream) throws IOException {
                        OutputStreamWriter writer = new OutputStreamWriter(outstream, "UTF-8");
                        String resp = "Hello";
            
                        writer.write(resp);
                        writer.flush();
                }
	        });
                
            ((EntityTemplate)entity).setContentType("text/html");
            response.setEntity(entity);
            */	      
        	
		} catch (Exception e) {
			Log.e(logName, "doProxy()\n" + e.toString());
			e.printStackTrace();
		}
				
		
		Log.d(logName, "Completed Request: " + destUri);
	}
	
	private String getDestinationUrl(String[] ss) {
		int i = 2;
		String destUri = "";
		for (i = 2; i < ss.length; i++) {
			if (i > 2) {
				destUri = destUri + "/";
			}
			
			destUri = destUri + ss[i];
		}
		
		return(destUri);
	}
	
	private String listAllHeader(Header[] hh) {
		StringBuffer sb = new StringBuffer();
		for (Header h : hh) {
			sb.append(h.getName() + ": " + h.getValue() + "\n");
		}
		
		return(sb.toString());
	}
	
}
